package util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 执行JSON数据处理（线程安全）。
 * 
 * @author Luffy
 * 
 */
public class JsonUtils {
    private static final Logger logger = LoggerFactory
            .getLogger(JsonUtils.class);

    // create once, reuse
    protected static final ObjectMapper mapper = new ObjectMapper();

    static {
        // faster this way, not default
        mapper.configure(MapperFeature.USE_STATIC_TYPING, true);
        // to prevent exception when encountering unknown property:
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    }

    /**
     * 将请求参数赋值给指定类型的对象。<br>
     * 规定：<br>
     * 1. 只处理参数名称与目标对象字段名称匹配的。<br>
     * 2. 只处理参数值是字符串类型的，并对字符串做了trimToNull处理。 <br>
     * 3. 只处理参数值非空的。<br>
     * 
     * @param request
     * @param toValueType
     * @return
     */
    public static <T> T processRequestParams(HttpServletRequest request,
            Class<T> toValueType) {
        Map<String, String[]> paramMap = request.getParameterMap();
        Map<String, String> strParamMap = new HashMap<String, String>();
        for (Entry<String, String[]> entry : paramMap.entrySet()) {
            String[] values = entry.getValue();
            String value = null;
            if (values != null && values.length == 1) {
                value = StringUtils.trimToNull(values[0]);
            }
            if (StringUtils.isNotBlank(value)) {
                strParamMap.put(entry.getKey(), value);
            }
        }
        return convertValue(strParamMap, toValueType);
    }

    /**
     * POJO-to-POJO
     * 
     * @param fromValue
     * @param toValueType
     * @return
     */
    public static <T> T convertValue(Object fromValue, Class<T> toValueType) {
        try {
            return mapper.convertValue(fromValue, toValueType);
        }
        catch (IllegalArgumentException e) {
            logger.error(
                    "convertValue: Unable to serialize to json: " + fromValue,
                    e);
            return null;
        }
    }

    /**
     * 将以指定分隔符分隔的字符串转换为对象数组，转换失败返回null。<br>
     * 支持： String->String[]; 数字String->Long[];
     * 
     * @param str
     * @param separatorChars
     * @param toValueType
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T convertStr2Array(String str, String separatorChars,
            Class<T> toValueType) {
        try {
            String[] values = StringUtils.split(str, separatorChars);
            // 目标类型是字符串数组直接返回
            if (toValueType.isAssignableFrom(String[].class)) {
                return (T) values;
            }
            return mapper.convertValue(values, toValueType);
        }
        catch (IllegalArgumentException e) {
            logger.error("convertStr2Array: Unable to String-to-POJO: " + str,
                    e);
            return null;
        }
    }

    /**
     * 将java对象转换成json字符串。<br>
     * 1）普通对象转换 2）Map集合转换 3）List集合转换
     * 
     * @param object
     *            java对象
     * @return json字符串
     */
    public static String writeObject2JSON(Object object) {
        try {
            return mapper.writeValueAsString(object);
        }
        catch (JsonProcessingException e) {
            logger.error(
                    "writeObject2JSON: Unable to serialize to json: " + object,
                    e);
            return StringUtils.EMPTY;
        }
    }

    /**
     * 将json字符串转换成JavaBean对象。
     * 
     * @param json
     *            json字符串
     * @param returnType
     *            java对象类型
     * @return
     */
    public static <T> T readJson2Entity(String json, Class<T> returnType) {
        try {
            return mapper.readValue(json, returnType);
        }
        catch (Exception e) {
            logger.error("readJson2Entity: Exception during deserializing from "
                    + StringUtils.abbreviate(json, 180),e);
            return null;
        }
    }

    /**
     * 将json字符串转换成List<Map>集合。
     * 
     * @param json
     *            json字符串
     * @return
     */
    @SuppressWarnings("unchecked")
    public static List<Map<String, Object>> readJson2List(String json) {
        try {
            return mapper.readValue(json, List.class);
        }
        catch (Exception e) {
            logger.error("readJson2List: Exception during deserializing from "
                    + StringUtils.abbreviate(json, 180));
            return null;
        }
    }

    /**
     * Json转化成List。
     * 
     * @param jsonArrayStr
     * @param clazz
     * @return
     */
    public static <T> List<T> readJson2List(String jsonArrayStr,
            Class<T> clazz) {
        List<T> result = new ArrayList<T>();
        try {
            List<Map<String, Object>> list = readJson2List(jsonArrayStr);
            if (list != null && !list.isEmpty()) {
                for (Map<String, Object> map : list) {
                    result.add(convertValue(map, clazz));
                }
            }
            return result;
        }
        catch (Exception e) {
            logger.error("readJson2List: Exception during deserializing from "
                    + StringUtils.abbreviate(jsonArrayStr, 180));
        }
        return result;
    }

    /**
     * Json字符串转换成Array数组。
     * 
     * @param json
     *            json字符串
     * @param returnType
     *            java对象类型
     * @return
     */
    public static <T> T[] readJson2Array(String json, Class<T[]> returnType) {
        try {
            return (T[]) mapper.readValue(json, returnType);
        }
        catch (Exception e) {
            logger.error("readJson2Array: Exception during deserializing from "
                    + StringUtils.abbreviate(json, 180));
            return null;
        }
    }

    /**
     * Json字符串转换成Map集合。
     * 
     * @param json
     *            json字符串
     * @param returnType
     *            java对象类型
     * @return
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Map<String, Object>> readJson2Map(String json) {
        try {
            return (Map<String, Map<String, Object>>) mapper.readValue(json,
                    Map.class);
        }
        catch (Exception e) {
            logger.error("readJson2Map: Exception during deserializing from "
                    + StringUtils.abbreviate(json, 180));
            return null;
        }
    }

    /**
     * Json转化成Map（指定Bean类型）。
     * 
     * @param json
     * @param clazz
     * @return
     */
    public static <T> Map<String, T> readJson2Map(String json, Class<T> clazz) {
        Map<String, T> result = new HashMap<String, T>();
        try {
            Map<String, Map<String, Object>> map = readJson2Map(json);
            if (map != null) {
                for (Entry<String, Map<String, Object>> entry : map
                        .entrySet()) {
                    result.put(entry.getKey(),
                            convertValue(entry.getValue(), clazz));
                }
            }
        }
        catch (Exception e) {
            logger.error("readJson2Map: Exception during deserializing from "
                    + StringUtils.abbreviate(json, 180));
        }
        return result;
    }

    /**
     * 获取JSON字符串中指定字段的内容。
     * 
     * @param json
     * @param fieldName
     * @return
     */
    public static String getFieldStrValue(String json, String fieldName) {
        Map<String, String> map = readJson2Map(json, String.class);
        return map.get(fieldName);
    }

}
